import { Injectable } from '@angular/core';

@Injectable({providedIn: 'root'})
export class WebGLService {
    private glProgramMap = new WeakMap<WebGLRenderingContext, WebGLProgram>();
    constructor() { }

    getGLContext (canvas: HTMLCanvasElement) {
        return canvas.getContext('webgl');
    }

    getProgramByGLContext (gl: WebGLRenderingContext) {
        return this.glProgramMap.get(gl);
    }

    initShader (gl: WebGLRenderingContext, vShaderSource: string, fShaderSource: string) {
        var program = this.createProgram(gl, vShaderSource, fShaderSource);
        if (!program) {
            console.error('Failed to create program');
            return false;
        }

        gl.useProgram(program);
        // gl.program = program;
        this.glProgramMap.set(gl, program);

        return true;
    }

    createProgram (gl: WebGLRenderingContext, vShaderSource: string, fShaderSource: string) {
        // 创建 shader 对象
        const vertexShader = this.loadShader(gl, gl.VERTEX_SHADER, vShaderSource);
        const fragmentShader = this.loadShader(gl, gl.FRAGMENT_SHADER, fShaderSource);
        if (!vertexShader || !fragmentShader) {
            return null;
        }

        // 创建 program 对象
        const program = gl.createProgram();
        if (!program) {
            return null;
        }

        // Attach the shader objects
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);

        // Link the program object
        gl.linkProgram(program);

        // Check the result of linking
        const linked = gl.getProgramParameter(program, gl.LINK_STATUS);
        if (!linked) {
            const error = gl.getProgramInfoLog(program);
            console.log('Failed to link program: ' + error);
            gl.deleteProgram(program);
            gl.deleteShader(fragmentShader);
            gl.deleteShader(vertexShader);
            return null;
        }
        return program;
    }

    loadShader(gl: WebGLRenderingContext, type: number, source: string): WebGLShader {
        // 创建 shader
        const shader = gl.createShader(type);
        if (shader == null) {
          console.log('unable to create shader');
          return null;
        }
      
        // 设置 shader 程序
        gl.shaderSource(shader, source);
      
        // 编译 shader
        gl.compileShader(shader);
      
        // shader 编译是否通过
        const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
        if (!compiled) {
          const error = gl.getShaderInfoLog(shader);
          console.log('Failed to compile shader: ' + error);
          gl.deleteShader(shader);
          return null;
        }
      
        return shader;
    }
}

